Skip to content

Disable gzip compression for float NIfTI intermediates#285

Merged
nx10 merged 2 commits into
mainfrom
feat/uncompressed-nifti-intermediates
Apr 9, 2026
Merged

Disable gzip compression for float NIfTI intermediates#285
nx10 merged 2 commits into
mainfrom
feat/uncompressed-nifti-intermediates

Conversation

@nx10
Copy link
Copy Markdown
Contributor

@nx10 nx10 commented Apr 9, 2026

Summary

  • Write intermediate float volumes as uncompressed .nii instead of .nii.gz to avoid gzip overhead on data that is read back immediately
  • Replace fslsplit with nibabel four_to_three in split_4d(), which also removes a container call
  • Integer and binary masks are left compressed since they compress efficiently

Changed intermediates

Location Intermediate Why
common.py:split_4d() per-volume splits Hundreds of float 3D volumes in a tight loop (biggest win)
resampling.py vol_*_motion.nii, vol_*_template.nii Per-volume ANTs outputs merged immediately
longitudinal/transform.py vol_*_template.nii Same pattern as resampling
motion.py slice.nii Float BOLD reference, read once by 3dvolreg
masking.py probseg_transform, bold_ref_dir_corrected, ref_bold_corrected, ref_bold_corrected_brain_masked, uni Float intermediates in chained masking pipeline
distortion.py phasediff, merged_epi Float intermediates consumed immediately

Test plan

  • Unit tests pass (725/725)
  • Ruff + mypy clean
  • Compare full pipeline CI duration against recent main runs

Closes #252

Write intermediate float volumes as uncompressed .nii instead of .nii.gz
to avoid gzip overhead on data that is read back immediately. Integer and
binary masks are left compressed since they compress efficiently.

- Replace fslsplit with nibabel four_to_three in split_4d (also removes
  a container call)
- Use .nii for per-volume ANTs outputs in resampling and longitudinal
  transform loops
- Use .nii for motion reference slice, masking float intermediates,
  and distortion correction float intermediates

Closes #252
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 9, 2026

Coverage

Coverage Report
FileStmtsMissCoverMissing
rbc
   __init__.py10100% 
   context.py25868%70, 75–77, 79–80, 93–94
   metadata.py560100% 
rbc/bids
   __init__.py90100% 
   _schema.py585499%776, 782, 790, 1101
   anatomical.py24387%44, 47–48
   builder.py72790%233–235, 362, 364–365, 386
   functional.py42588%46–49, 84
   longitudinal.py250100% 
   metrics.py23195%44
   qc.py170100% 
   query.py674237%103–107, 121–125, 127–128, 130–135, 137, 139, 153, 159–165, 198, 207, 209–216, 225, 257, 266–267
   session.py470100% 
rbc/cli
   __init__.py10100% 
   all.py49295%84, 108
   anatomical.py25292%47, 62
   base.py67888%55, 115–117, 123–125, 148
   functional.py33293%67, 86
   longitudinal.py27292%46, 62
   main.py410100% 
   metrics.py42295%77, 94
   qc.py25292%45, 60
rbc/core
   __init__.py30100% 
   common.py261253%43–45, 62–70
   fileops.py27485%69–72
   fsl2itk.py420100% 
   nifti.py192597%236–237, 244–245, 524
   niwrap.py56198%58
rbc/core/anatomical
   __init__.py40100% 
   registration.py15473%59, 151, 166, 183
   segmentation.py24866%64, 74–76, 92, 114, 125, 141
rbc/core/functional
   __init__.py130100% 
   coregistration.py7271%44, 55
   despiking.py7357%32, 36–37
   distortion.py1304069%269–271, 321, 324, 332–335, 341–346, 349, 352–353, 356, 365–369, 375–376, 387–388, 391, 397, 443–444, 447, 455, 461, 470–471, 474, 484, 491
   erosion.py32196%50
   initialization.py9455%35, 42–43, 63
   masking.py342526%53, 55–56, 58–59, 62–65, 69, 91, 134, 183, 197, 208, 223, 233, 249, 258, 271, 285, 296, 306, 319, 328
   motion.py573735%62, 64–67, 69, 71, 73, 76–77, 83–84, 86–87, 95–97, 99, 102, 105, 107, 124–125, 135–138, 159, 169, 171–172, 175, 177–179, 181, 183
   nuisance.py816025%78, 80–85, 87, 89–90, 93, 96–98, 100–102, 104–110, 112–116, 118, 163, 165, 167, 170–171, 173–175, 178, 181–182, 185–187, 190–193, 197, 203–205, 207, 235, 243, 269, 278, 307, 316, 322
   regressors.py89693%163, 193, 325–328
   resampling.py544320%37–42, 74–76, 78, 80–81, 85–87, 90, 93, 105, 107–108, 112, 114, 150–152, 154–155, 159, 161–162, 167–169, 173–174, 177, 180, 187, 199, 201–202, 207, 209
   timing.py161131%46–47, 49–53, 58, 60, 66–67
rbc/core/longitudinal
   __init__.py10100% 
   transform.py46784%106–107, 165–168, 170
rbc/core/metrics
   __init__.py30100% 
   alff.py90198%265
   reho.py660100% 
   smoothing.py7357%36, 42–43
   standardization.py271159%64, 66–68, 70, 72–75, 77–78
   timeseries.py57198%120
rbc/core/qc
   __init__.py60100% 
   dvars.py260100% 
   motion.py310100% 
   registration.py410100% 
   xcp.py410100% 
rbc/orchestration
   __init__.py31293%88, 91
   all.py412343%76–78, 80–81, 85, 92, 95, 100, 103, 111, 121, 123–124, 129, 137, 145–146, 163, 165–166, 168, 170
   anatomical.py372240%49–52, 57–58, 60–63, 85–87, 89–90, 94, 101, 104, 109–110, 116, 118
   functional.py392341%60–62, 64–65, 67, 69, 84–86, 88, 116–118, 120–121, 125, 131, 134, 139–140, 149, 151
   longitudinal.py56198%150
   metrics.py463034%32–35, 38–40, 67, 75–76, 100–102, 104–106, 110, 118–121, 123–124, 130–132, 137, 145, 152, 154
   qc.py340100% 
rbc/workflows
   __init__.py100100% 
   anatomical.py471959%90–93, 97–102, 107, 177–180, 182–184, 188
   functional.py985642%113–114, 122, 127–128, 136, 207–208, 211–212, 215–216, 219, 222–225, 235–237, 247–248, 251, 254, 257–258, 266–267, 274–275, 282–283, 290–291, 294–296, 299–302, 314–315, 327, 329–332, 335–336, 345–346, 354, 361, 430, 436
   metrics.py391756%80–81, 86–87, 90–93, 96–99, 103–106, 108
   qc.py533337%87, 89–90, 93, 96, 99–104, 107, 116–118, 122–125, 127–131, 133–134, 136–138, 141, 158, 165, 167
rbc_resources
   __init__.py380100% 
TOTAL323260581% 

Tests Skipped Failures Errors Time
726 0 💤 0 ❌ 0 🔥 10.075s ⏱️

FSL uses FSLOUTPUTTYPE to determine the output format, ignoring the
filename extension. Keep fslmaths outputs as .nii.gz since the Docker
container defaults to NIFTI_GZ.
@nx10 nx10 marked this pull request as ready for review April 9, 2026 13:52
@nx10 nx10 requested review from jpillai00 and kaitj April 9, 2026 13:52
Copy link
Copy Markdown
Contributor

@kaitj kaitj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In principle, I think I agree with this. Do we have a general idea of how much of a difference there is between the compressed and uncompressed file sizes?

@nx10
Copy link
Copy Markdown
Contributor Author

nx10 commented Apr 9, 2026

CI reported intermediate dir size 6.3GB before and after these changes so <100MB - generally I picked non/hard compressible float array niftis so this is not surprising

@nx10 nx10 merged commit eccd701 into main Apr 9, 2026
8 checks passed
@nx10 nx10 deleted the feat/uncompressed-nifti-intermediates branch April 9, 2026 14:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Consider disabling gzip compression for certain nifti intermediates

2 participants